<template>
    <el-tree class="tnxel-permission-tree px-1 py-2"
        ref="tree"
        :data="nodes"
        :default-expand-all="defaultExpandAll"
        :expand-on-click-node="false"
        node-key="id"
        :style="{'max-height': maxHeight}"
        v-if="menu"
    >
        <template #default="{node, data}">
            <div class="tnxel-permission-node">
                <el-checkbox v-model="data.checked" v-if="data.permission" @change="() => {
                    onCheckChange(data);
                }">{{ data.label }}
                </el-checkbox>
                <span v-else-if="node">{{ data.label }}</span>
                <span class="text-muted" :class="{'d-none': !data.remark}">({{ data.remark }})</span>
            </div>
        </template>
    </el-tree>
    <div class="tnxel-permission-loading" v-else>
        <i class="el-icon-loading"></i>
    </div>
</template>

<script>
function addMenuItemToTreeNodes(parentId, menuItems, treeNodes, permissions) {
    for (let i = 0; i < menuItems.length; i++) {
        const item = menuItems[i];
        if (item.caption) { // 有显示名称才可进行权限分配，否则只是一个隐藏的菜单项
            let node = {
                id: (parentId || 'node') + '-' + i,
                parentId: parentId,
                label: item.caption,
                path: item.path,
                permission: item.permission,
                checked: item.permission && permissions && permissions.contains(item.permission),
                remark: item.desc || item.permissionCaption,
            };
            if (item.subs && item.subs.length) {
                node.children = node.children || [];
                addMenuItemToTreeNodes(node.id, item.subs, node.children, permissions);
            }
            treeNodes.push(node);
        }
    }
}

function getTreeNodes(menu, permissions) {
    const nodes = [];
    if (menu) {
        let items = menu.getAssignableItems();
        addMenuItemToTreeNodes(undefined, items, nodes, permissions);
    }
    return nodes;
}

function addCheckedNodePermissionTo(app, nodes, permissions) {
    for (let node of nodes) {
        if (node.checked && node.permission) {
            let permission = node.permission;
            if (app) {
                permission = app + '.' + permission;
            }
            permissions.push(permission);
        }
        if (node.children) {
            addCheckedNodePermissionTo(app, node.children, permissions);
        }
    }
}

function setCheckedByPermission(nodes, permission, checked) {
    if (nodes && permission) {
        for (let node of nodes) {
            if (node.permission === permission) {
                node.checked = checked;
            }
            setCheckedByPermission(node.children, permission, checked);
        }
    }
}

export default {
    name: 'TnxelPermissionTree',
    props: {
        menu: Object,
        permissions: Array,
        maxHeight: String,
        defaultExpandAll: {
            type: Boolean,
            default: true,
        },
    },
    data() {
        return {
            nodes: getTreeNodes(this.menu, this.permissions)
        };
    },
    watch: {
        menu(menu) {
            this.nodes = getTreeNodes(menu, this.permissions);
        },
        permissions(permissions) {
            this.nodes = getTreeNodes(this.menu, permissions);
        }
    },
    methods: {
        getNode(nodeId, nodes) {
            if (nodeId) {
                nodes = nodes || this.nodes;
                for (let node of nodes) {
                    if (node.id === nodeId) {
                        return node;
                    }
                    if (node.children) {
                        let child = this.getNode(nodeId, node.children);
                        if (child) {
                            return child;
                        }
                    }
                }
            }
            return undefined;
        },
        onCheckChange(node) {
            if (node.checked) { // 节点被选中，则上级节点必须选中
                let parentNode = this.getNode(node.parentId);
                if (parentNode) {
                    parentNode.checked = true;
                    setCheckedByPermission(this.nodes, parentNode.permission, true);
                }
            } else { // 节点未选中，则下级节点必须全部未选中
                if (node.children) {
                    node.children.forEach(child => {
                        child.checked = false;
                        setCheckedByPermission(this.nodes, child.permission, false);
                    });
                }
            }
            setCheckedByPermission(this.nodes, node.permission, node.checked);
        },
        getPermissions(withApp) {
            let app = withApp ? this.menu.app : null;
            const permissions = [];
            addCheckedNodePermissionTo(app, this.nodes, permissions);
            return permissions;
        },
        setAllChecked(checked, parentNode) {
            let nodes = parentNode ? parentNode.children : this.nodes;
            if (nodes) {
                for (let node of nodes) {
                    if (node.permission) {
                        node.checked = checked;
                    }
                    this.setAllChecked(checked, node);
                }
            }
        },
    }
}
</script>

<style>
.tnxel-permission-tree {
    overflow-y: auto;
}

.tnxel-permission-tree .tnxel-permission-node {
    width: 100%;
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding-right: 10px;
}

.tnxel-permission-tree .tnxel-permission-node > :last-child {
    margin-left: 6px;
    margin-right: 6px;
    white-space: normal;
    line-height: 1;
    text-align: right;
}
</style>
